#include "GlobalData/GlobalData.h"
#include "Input/Parser.h"


long KeyDownProc( Window& win, long wparam, long lparam ) {
  gInput.SetDown( wparam );
  return 0;
}

long KeyUpProc( Window& win, long wparam, long lparam ) {
  gInput.SetUp( wparam );
  return 0;
}

long LeftMouseDownProc( Window& win, long wparam, long lparam ) {
  gInput.SetDown( WM_LBUTTONDOWN );
  return 0;
}

long LeftMouseUpProc( Window& win, long wparam, long lparam ) {
  gInput.SetUp( WM_LBUTTONDOWN );
  return 0;
}

long RightMouseDownProc( Window& win, long wparam, long lparam ) {
  gInput.SetDown( WM_RBUTTONDOWN );
  return 0;
}

long RightMouseUpProc( Window& win, long wparam, long lparam ) {
  gInput.SetUp( WM_RBUTTONDOWN );
  return 0;
}

#include "windowsx.h" // GET_#_PARAM
long MouseMoveProc( Window& win, long wparam, long lparam ) {
  float normX = GET_X_LPARAM(lparam) / (float)gWindow.GetWidth(); 
  float normY = GET_Y_LPARAM(lparam) / (float)gWindow.GetHeight();

  normX -= .5f;
  normY -= .5f;

  normX *= 15;
  normY *= 15;

  normX = ((normX < 0) ? -1 : 1) * (abs(normX)+.5f);
  normY = ((normY > 0) ? -1 : 1) * (abs(normY)+.5f);

  gMouseX = normX;
  gMouseY = normY;
  return 0;
}

void CurrentStateProc() {
  std::cout << "Current States:" << std::endl;
  std::cout << "  ";
  gPause = !gPause;
  PauseSwitchProc();

  std::cout << "  ";
  gTabDown = !gTabDown;
  TabDownSwitchProc();

  std::cout << "  ";
  gChangeAttribute = !gChangeAttribute;
  ChangingAttributeSwitchProc();

  std::cout << "  ";
  gTrackingOn = !gTrackingOn;
  TrackingSwitchProc();

  std::cout << "  ";
  std::cout << "Currently using Adjustable Files Group " << gCurrentFile << "." << std::endl << std::endl;
}

void PauseSwitchProc() {
  gPause = !gPause;
  if( gPause ) {
    std::cout << "Simulation paused!" << std::endl << std::endl;
  }
  else {
    std::cout << "Simulation unpaused!" << std::endl << std::endl;
  }
}

void TabDownSwitchProc() {
  gTabDown = !gTabDown;
  if( gTabDown ) {
    std::cout << "Able to place objects/agents!" << std::endl << std::endl;
  }
  else {
    std::cout << "Click location to view object/agent." << std::endl << std::endl;
  }
}

void ChangingAttributeSwitchProc() {
  gChangeAttribute = !gChangeAttribute;
  if( gChangeAttribute ) {
    std::cout << gAttributeName << " attribute is incrementing." << std::endl << std::endl;
  }
  else {
    std::cout << "Receptor value " << gAttributeName << " is not changing." << std::endl << std::endl;
  }
}

void TrackingSwitchProc() {
  gTrackingOn = !gTrackingOn;
  if( gTrackingOn ) {
    std::cout << "Tracking agent: ";
    if( gTargetAgent ) {
      std::cout << gTargetAgent->brain.GetName();
    }
    else {
      std::cout << "No Agent Selected";
    }
    std::cout << std::endl << std::endl;
  }
  else {
    std::cout << "Agent tracking is off:" << std::endl << std::endl;
  }
}

void ChangeToFile1() { std::cout << "Using Adjustable Files Group 1." << std::endl << std::endl; gCurrentFile = 1; }
void ChangeToFile2() { std::cout << "Using Adjustable Files Group 2." << std::endl << std::endl; gCurrentFile = 2; }
void ChangeToFile3() { std::cout << "Using Adjustable Files Group 3." << std::endl << std::endl; gCurrentFile = 3; }
void ChangeToFile4() { std::cout << "Using Adjustable Files Group 4." << std::endl << std::endl; gCurrentFile = 4; }
void ChangeToFile5() { std::cout << "Using Adjustable Files Group 5." << std::endl << std::endl; gCurrentFile = 5; }
void ChangeToFile6() { std::cout << "Using Adjustable Files Group 6." << std::endl << std::endl; gCurrentFile = 6; }
void ChangeToFile7() { std::cout << "Using Adjustable Files Group 7." << std::endl << std::endl; gCurrentFile = 7; }
void ChangeToFile8() { std::cout << "Using Adjustable Files Group 8." << std::endl << std::endl; gCurrentFile = 8; }
void ChangeToFile9() { std::cout << "Using Adjustable Files Group 9." << std::endl << std::endl; gCurrentFile = 9; }

void PrintObjectOnMap( int x, int y ) {
  ObjectModel* obj = gWorldMap.WorldGrid[y+7][x+7].Object;
  if( obj && !gWorldMap.WorldGrid[y+7][x+7].IsWall ) {
    SmartObject& brain = obj->brain;

    const SmartObject::StimSet& stimSet = brain.GetStimulants();
    SmartObject::StimIter stimIter = stimSet.begin();
    SmartObject::StimIter stimEnd = stimSet.end();

    std::cout << brain.GetName() << std::endl;
    std::cout << "  Location: " << "X = " << obj->GetPosition()[0] << std::endl;
    std::cout << "            " << "Y = " << obj->GetPosition()[1] << std::endl;
    while( stimIter != stimEnd ) {
      std::cout << "  " << gSmartObjectIDGenerator.GetName( stimIter->attributeID ) << 
                   ": " << stimIter->weight << std::endl;
      ++stimIter;
    }
    std::cout << std::endl;
  }
}

AgentModel* SelectAgent( float x, float y ) {
  // Selects the closest agent to the mouse location
  // Mouse must be within a unit range ( circle in a 1x1 box )
  WorldMap::AgtList* agtList = gWorldMap.GetAgents();
  WorldMap::AgtIter iter = agtList->begin();
  WorldMap::AgtIter end = agtList->end();

  AgentModel* ptr = NULL;
  float distance = .5f;

  // Fix offsets
  x += (x<0)? .5f : -.5f;
  y += (y<0)? .5f : -.5f;

  while( iter != end ) {
    float magnitude = ( (*iter)->GetPosition() - NewVector( x, y ) ).Magnitude();
    if( magnitude < distance ) {
      ptr = (*iter);
      distance = magnitude;
    }

    ++iter;
  }

  if( ptr ) {
    return ptr;
  }

  return NULL;
}

void PrintAgentOnMap( float x, float y ) {
  AgentModel* agt = SelectAgent( x, y );
  if( agt ) {
    gTargetAgent = agt;
    SmartAgent& brain = agt->brain;

    const SmartAgent::RecepSet& recepSet = brain.GetReceptors();
    SmartAgent::RecepIter recepIter = recepSet.begin();
    SmartAgent::RecepIter recepEnd = recepSet.end();

    std::cout << brain.GetName() << std::endl;
    std::cout << "  Location: " << "X = " << agt->GetPosition()[0] << std::endl;
    std::cout << "            " << "Y = " << agt->GetPosition()[1] << std::endl;
    while( recepIter != recepEnd ) {
      std::cout << "  " << gSmartObjectIDGenerator.GetName( recepIter->attributeID ) << 
                   ": " << recepIter->currentState << std::endl;
      ++recepIter;
    }
    std::cout << std::endl;
  }
}

void AddObjectProc() {
  if( gTabDown ) {
    // Is it a valid location
    if( gWorldMap.IsWall( (int)gMouseX, (int)gMouseY ) && !gWorldMap.WorldGrid[int(gMouseY)+7][int(gMouseX)+7].Object ) {
      // Creating new object
      // What it should look like ( use gCurrentFile for choosing appropriate file )
      ObjectModel* temp = CreateNewObject( (int)gMouseX, (int)gMouseY );

      if( temp )
        gWorldMap.RegisterObject( *temp );
    }
  }
  else {
    PrintObjectOnMap( (int)gMouseX, (int)gMouseY );
  }
}

void AddAgentProc() {
  if( gTabDown ) {
    if( gWorldMap.IsWall( (int)gMouseX, (int)gMouseY ) && !gWorldMap.WorldGrid[int(gMouseY+7)][int(gMouseX+7)].Object ) {
      // Creating new Agent
      // What it should look like ( use gCurrentFile for choosing appropriate file )
      AgentModel* temp = CreateNewAgent( (int)gMouseX, (int)gMouseY );

      if( temp )
        gWorldMap.RegisterAgent( *temp );
    }
  }
  else {
    PrintAgentOnMap( gMouseX, gMouseY );
  }
}

void ResetMap() {
  gTargetAgent = NULL;
  std::cout << "Resetting Map!" << std::endl << std::endl;
  gWorldMap.ClearMap();
}

void ResetObjects() {
  std::cout << "Resetting Objects!" << std::endl << std::endl;
  gWorldMap.ClearObjects();
}

void ResetAgents() {
  gTargetAgent = NULL;
  std::cout << "Resetting Agents!" << std::endl << std::endl;
  gWorldMap.ClearAgents();
}
